package com.oyjd.framework.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.oyjd.framework.log.MyLog;

import android.annotation.SuppressLint;

/**
 * 从网络上获取数据
 * 
 * @author 欧建东
 * @email oyjd@163.com
 * 
 */
@SuppressLint("DefaultLocale")
public class HttpNet {

	private static final String encoding = "utf-8";// 字符编码
	private static final String boundary = "----" + System.currentTimeMillis();// 数据分隔符

	private static String PROXY_URL;// 代理地址
	private static int PROXY_PORT;// 代理端口

	public static Map<String, String> HEAD_MAP = new HashMap<String, String>();// 客户设置的头
	public static String session = null;// session

	/**
	 * 设置代理
	 * 
	 * @param proxyUrl
	 *            代理地址
	 * @param proxyPort
	 *            代理端口
	 */
	public static void setProxy(String proxyUrl, int proxyPort) {
		PROXY_URL = proxyUrl;
		PROXY_PORT = proxyPort;
	}

	/**
	 * 获取特定网络地址的字节数组
	 * 
	 * @param url
	 *            网络地址
	 * @return
	 * @throws Exception
	 */
	public static byte[] getBytesFromNet(String url) throws Exception {
		return getBytesFromNet(url, null);
	}

	/**
	 * 获取特定网络地址的字节数组
	 * 
	 * @param url
	 *            网络地址
	 * @param para
	 *            需要post的参数map
	 * @return
	 * @throws Exception
	 */
	@SuppressLint("DefaultLocale")
	public static byte[] getBytesFromNet(String url, Map<String, Object> para) throws Exception {
		MyLog.i("HttpNet", "url-->" + url);

		byte[] result = null;
		HttpURLConnection connection = null;

		// ============== 处理资源请求
		// 请求类型，true--post ，false---get
		boolean postFlag = null != para && para.size() > 0;

		// 设置请求协议头
		URL postUrl = new URL(url);

		if (null != PROXY_URL) {
			Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_URL, PROXY_PORT));
			connection = (HttpURLConnection) postUrl.openConnection(proxy);
		} else {
			connection = (HttpURLConnection) postUrl.openConnection();
		}
		connection.setConnectTimeout(5000);
		connection.setDefaultUseCaches(false);
		// connection.setDoOutput(true);
		// connection.setDoInput(true);
		connection.setRequestMethod(postFlag ? "POST" : "GET");
		connection.setRequestProperty("Charset", encoding);// 设置请求的编码方式
		if (null != session) {
			connection.setRequestProperty("Cookie", session);
		}
		// 加入自定义协议头
		for (String key : HEAD_MAP.keySet()) {
			connection.setRequestProperty(key, HEAD_MAP.get(key));
		}

		if (postFlag) {
			// 分解普通参数和文件参数
			boolean mutiFlag = false;
			Map<String, Object> map_normal = new HashMap<String, Object>();
			Map<String, UploadFileVO> map_file = new HashMap<String, UploadFileVO>();
			for (String key : para.keySet()) {
				Object value = para.get(key);
				if (value instanceof UploadFileVO) {
					map_file.put(key, (UploadFileVO) value);
					mutiFlag = true;
				} else {
					map_normal.put(key, value);
				}
			}
			if (mutiFlag) {
				connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
				connection.connect();
				// 合成请求协议体输出
				postByMultipart(connection.getOutputStream(), map_normal, map_file);
			} else {
				connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
				connection.connect();
				// 合成请求协议体输出
				postByFormUrlencoded(connection.getOutputStream(), map_normal);
			}
		} else {
			connection.setRequestProperty("Content-Type", "text/html");
			connection.connect();
		}

		// ============== 处理回应结果
		int code = connection.getResponseCode();
		if (200 != code) {
			return result;
		}
		// 处理回应的协议头：cookie
		if (null == session) {
			String tmpsession = "";
			Map<String, List<String>> m = connection.getHeaderFields();
			for (Iterator<String> item = m.keySet().iterator(); item.hasNext();) {
				String key = item.next();
				if (null != key && "set-cookie".equals(key.toLowerCase())) {
					List<String> list = m.get(key);
					if (null != list && list.size() > 0) {
						for (String s : list) {
							tmpsession += s + ";";
						}
					}
					session = tmpsession;
					break;
				}
			}
		}

		// 处理回应的协议体
		InputStream inputStream = connection.getInputStream();
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = inputStream.read(buffer, 0, 1024)) != -1) {
			outStream.write(buffer, 0, len);
		}
		result = outStream.toByteArray();
		outStream.close();
		inputStream.close();
		connection.disconnect();
		return result;
	}

	/**
	 * 以x-www-form-urlencoded方式提交，合成协议体
	 * 
	 * @param out
	 *            输出流
	 * @param map_normal
	 *            普通表单字段map
	 * @throws IOException
	 */
	private static void postByFormUrlencoded(OutputStream out, Map<String, Object> map_normal) throws IOException {
		// 合成POST参数
		StringBuffer sb = new StringBuffer();
		for (String key : map_normal.keySet()) {
			Object val = map_normal.get(key);
			if (val instanceof String) {
				sb.append("&");
				sb.append(key);
				sb.append("=");
				sb.append(URLEncoder.encode((String) val, encoding));
			} else if (val instanceof String[]) {
				String[] tvs = (String[]) val;
				for (String tv : tvs) {
					sb.append("&");
					sb.append(key);
					sb.append("=");
					sb.append(URLEncoder.encode((String) tv, encoding));
				}
			}
		}

		String postData = sb.substring(1);
		byte[] b = postData.getBytes();
		out.write(b, 0, b.length);
		out.flush();
		out.close();
	}

	/**
	 * 以Multipart方式提交，附带文件提交，合成协议体
	 * 
	 * @param out
	 *            输出流
	 * @param map_normal
	 *            普通表单字段map
	 * @param map_file
	 *            文件表单字段map
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 */
	private static void postByMultipart(OutputStream out, Map<String, Object> map_normal, Map<String, UploadFileVO> map_file) throws UnsupportedEncodingException, IOException {
		// 普通的表单字段内容
		StringBuilder sb = new StringBuilder();
		for (String key : map_normal.keySet()) {
			Object val = map_normal.get(key);
			if (val instanceof String) {
				sb.append("--");
				sb.append(boundary);
				sb.append("\r\nContent-Disposition: form-data; name=\"");
				sb.append(key);
				sb.append("\"\r\n\r\n");
				sb.append((String) val);
				sb.append("\r\n");
			} else if (val instanceof String[]) {
				String[] tvs = (String[]) val;
				for (String tv : tvs) {
					sb.append("--");
					sb.append(boundary);
					sb.append("\r\nContent-Disposition: form-data; name=\"");
					sb.append(key);
					sb.append("\"\r\n\r\n");
					sb.append((String) tv);
					sb.append("\r\n");
				}
			}

		}

		out.write(sb.toString().getBytes(encoding));
		out.flush();

		// 上传文件数据
		byte[] buffer = new byte[1024];
		for (String key : map_file.keySet()) {
			UploadFileVO vo = map_file.get(key);
			StringBuilder split = new StringBuilder();
			split.append("--");
			split.append(boundary);
			split.append("\r\nContent-Disposition: form-data; name=\"");
			split.append(key);
			split.append("\"; filename=\"");
			split.append(vo.getFileName());
			split.append("\"\r\nContent-Type: ");
			split.append(vo.getContentType());
			split.append("\r\n\r\n");
			out.write(split.toString().getBytes(encoding));
			// 写入文件字节体
			InputStream inputStream = vo.getInputStream();
			if (null != inputStream) {
				int len = 0;
				while ((len = inputStream.read(buffer)) != -1) {
					out.write(buffer, 0, len);
				}
				inputStream.close();
			}

			out.write("\r\n".getBytes(encoding));
			out.flush();
		}

		// 写结尾
		out.write(("--" + boundary + "--\r\n").getBytes(encoding));

		out.flush();
		out.close();
	}

	/**
	 * 上传网络文件的对象
	 * 
	 * @author 欧建东
	 * @email oyjd@163.com
	 * 
	 */
	public static class UploadFileVO {
		private String fileName;// 文件名
		private String contentType = "application/octet-stream";// 文件类型
		private InputStream inputStream;// 文件流

		public UploadFileVO() {
			super();
		}

		public UploadFileVO(String filePath) {
			this(new File(filePath));
		}

		public UploadFileVO(File file) {
			if (null != file && file.exists()) {
				try {
					this.inputStream = new FileInputStream(file);
					this.fileName = file.getName();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				}
			}

		}

		public UploadFileVO(String fileName, InputStream inputStream) {
			this.fileName = fileName;
			this.inputStream = inputStream;
		}

		public UploadFileVO(String fileName, String contentType, InputStream inputStream) {
			this.fileName = fileName;
			this.contentType = contentType;
			this.inputStream = inputStream;
		}

		public String getFileName() {
			return fileName;
		}

		public void setFileName(String fileName) {
			this.fileName = fileName;
		}

		public String getContentType() {
			return contentType;
		}

		public void setContentType(String contentType) {
			this.contentType = contentType;
		}

		public InputStream getInputStream() {
			return inputStream;
		}

		public void setInputStream(InputStream inputStream) {
			this.inputStream = inputStream;
		}

	}
}
